home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / curves.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-15  |  43.7 KB  |  1,818 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24.  
  25. #include <gtk/gtk.h>
  26.  
  27. #include "apptypes.h"
  28.  
  29. #include "appenv.h"
  30. #include "cursorutil.h"
  31. #include "drawable.h"
  32. #include "gdisplay.h"
  33. #include "gimphistogram.h"
  34. #include "gimpui.h"
  35. #include "curves.h"
  36. #include "gimplut.h"
  37.  
  38. #include "libgimp/gimpenv.h"
  39. #include "libgimp/gimpmath.h"
  40.  
  41. #include "libgimp/gimpintl.h"
  42.  
  43. #define GRAPH          0x1
  44. #define XRANGE_TOP     0x2
  45. #define XRANGE_BOTTOM  0x4
  46. #define YRANGE         0x8
  47. #define DRAW          0x10
  48. #define ALL           0xFF
  49.  
  50. /*  NB: take care when changing these values: make sure the curve[] array in
  51.  *  curves.h is large enough.
  52.  */
  53. #define GRAPH_WIDTH    256
  54. #define GRAPH_HEIGHT   256
  55. #define XRANGE_WIDTH   256
  56. #define XRANGE_HEIGHT   16
  57. #define YRANGE_WIDTH    16
  58. #define YRANGE_HEIGHT  256
  59. #define RADIUS           3
  60. #define MIN_DISTANCE     8
  61.  
  62. #define RANGE_MASK  GDK_EXPOSURE_MASK | \
  63.                     GDK_ENTER_NOTIFY_MASK
  64.  
  65. #define GRAPH_MASK  GDK_EXPOSURE_MASK | \
  66.             GDK_POINTER_MOTION_MASK | \
  67.             GDK_POINTER_MOTION_HINT_MASK | \
  68.                     GDK_ENTER_NOTIFY_MASK | \
  69.             GDK_BUTTON_PRESS_MASK | \
  70.             GDK_BUTTON_RELEASE_MASK | \
  71.             GDK_BUTTON1_MOTION_MASK
  72.  
  73. /*  the curves structures  */
  74.  
  75. typedef struct _Curves Curves;
  76.  
  77. struct _Curves
  78. {
  79.   gint x, y;    /*  coords for last mouse click  */
  80. };
  81.  
  82. typedef gdouble CRMatrix[4][4];
  83.  
  84. /*  the curves tool options  */
  85. static ToolOptions  * curves_options = NULL;
  86.  
  87. /*  the curves dialog  */
  88. static CurvesDialog * curves_dialog = NULL;
  89.  
  90. /*  the curves file dialog  */
  91. static GtkWidget *file_dlg = NULL;
  92. static gboolean   load_save;
  93.  
  94. static GtkWidget *channel_items[5];
  95.  
  96. static CRMatrix CR_basis =
  97. {
  98.   { -0.5,  1.5, -1.5,  0.5 },
  99.   {  1.0, -2.5,  2.0, -0.5 },
  100.   { -0.5,  0.0,  0.5,  0.0 },
  101.   {  0.0,  1.0,  0.0,  0.0 },
  102. };
  103.  
  104.  
  105. /*  curves action functions  */
  106.  
  107. static void   curves_button_press   (Tool *, GdkEventButton *, gpointer);
  108. static void   curves_button_release (Tool *, GdkEventButton *, gpointer);
  109. static void   curves_motion         (Tool *, GdkEventMotion *, gpointer);
  110. static void   curves_control        (Tool *, ToolAction,       gpointer);
  111.  
  112. static CurvesDialog * curves_dialog_new (void);
  113.  
  114. static void   curves_update           (CurvesDialog *, int);
  115. static void   curves_plot_curve       (CurvesDialog *, int, int, int, int);
  116. static void   curves_preview          (CurvesDialog *);
  117.  
  118. static void   curves_channel_callback (GtkWidget *, gpointer);
  119.  
  120. static void   curves_smooth_callback      (GtkWidget *, gpointer);
  121. static void   curves_free_callback        (GtkWidget *, gpointer);
  122.  
  123. static void   curves_channel_reset        (int);
  124. static void   curves_reset_callback       (GtkWidget *, gpointer);
  125. static void   curves_ok_callback          (GtkWidget *, gpointer);
  126. static void   curves_cancel_callback      (GtkWidget *, gpointer);
  127. static void   curves_load_callback        (GtkWidget *, gpointer);
  128. static void   curves_save_callback        (GtkWidget *, gpointer);
  129. static void   curves_preview_update       (GtkWidget *, gpointer);
  130. static gint   curves_xrange_events        (GtkWidget *, GdkEvent *, CurvesDialog *);
  131. static gint   curves_yrange_events        (GtkWidget *, GdkEvent *, CurvesDialog *);
  132. static gint   curves_graph_events         (GtkWidget *, GdkEvent *, CurvesDialog *);
  133. static void   curves_CR_compose           (CRMatrix, CRMatrix, CRMatrix);
  134.  
  135. static void   file_dialog_create          (GtkWidget *);
  136. static void   file_dialog_ok_callback     (GtkWidget *, gpointer);
  137. static void   file_dialog_cancel_callback (GtkWidget *, gpointer);
  138.  
  139. static gboolean  curves_read_from_file    (FILE *f);
  140. static void      curves_write_to_file     (FILE *f);
  141.  
  142.  
  143. /*  curves machinery  */
  144.  
  145. gfloat
  146. curves_lut_func (CurvesDialog *cd,
  147.          gint          nchannels,
  148.          gint          channel,
  149.          gfloat        value)
  150. {
  151.   gfloat f;
  152.   gint index;
  153.   gdouble inten;
  154.   gint j;
  155.  
  156.   if (nchannels == 1)
  157.     j = 0;
  158.   else
  159.     j = channel + 1;
  160.  
  161.   inten = value;
  162.  
  163.   /* For color images this runs through the loop with j = channel +1
  164.      the first time and j = 0 the second time */
  165.   /* For bw images this runs through the loop with j = 0 the first and
  166.      only time  */
  167.   for (; j >= 0; j -= (channel + 1))
  168.   {
  169.     /* don't apply the overall curve to the alpha channel */
  170.     if (j == 0 && (nchannels == 2 || nchannels == 4)
  171.     && channel == nchannels -1)
  172.       return inten;
  173.  
  174.     if (inten < 0.0)
  175.       inten = cd->curve[j][0]/255.0;
  176.     else if (inten >= 1.0)
  177.       inten = cd->curve[j][255]/255.0;
  178.     else /* interpolate the curve */
  179.     {
  180.       index = floor(inten * 255.0);
  181.       f = inten*255.0 - index;
  182.       inten = ((1.0 - f) * cd->curve[j][index    ] + 
  183.            (      f) * cd->curve[j][index + 1] ) / 255.0;
  184.     }
  185.   }
  186.   return inten;
  187. }
  188.  
  189. static void
  190. curves_colour_update (Tool           *tool,
  191.               GDisplay       *gdisp,
  192.               GimpDrawable   *drawable,
  193.               gint            x,
  194.               gint            y)
  195. {
  196.   guchar *color;
  197.   gint    offx;
  198.   gint    offy;
  199.   gint    maxval;
  200.   gboolean       has_alpha;
  201.   gboolean       is_indexed;
  202.   GimpImageType  sample_type;
  203.  
  204.   if(!tool || tool->state != ACTIVE)
  205.     return;
  206.  
  207.   drawable_offsets (drawable, &offx, &offy);
  208.  
  209.   x -= offx;
  210.   y -= offy;
  211.  
  212.   if (!(color = image_map_get_color_at(curves_dialog->image_map, x, y)))
  213.     return;
  214.  
  215.   sample_type = gimp_drawable_type (drawable);
  216.   is_indexed  = gimp_drawable_is_indexed (drawable);
  217.   has_alpha   = GIMP_IMAGE_TYPE_HAS_ALPHA (sample_type);
  218.  
  219.   curves_dialog->col_value[GIMP_HISTOGRAM_RED] = color[RED_PIX];
  220.   curves_dialog->col_value[GIMP_HISTOGRAM_GREEN] = color[GREEN_PIX];
  221.   curves_dialog->col_value[GIMP_HISTOGRAM_BLUE] = color[BLUE_PIX];
  222.  
  223.   if (has_alpha)
  224.     {
  225.       curves_dialog->col_value [GIMP_HISTOGRAM_ALPHA] = color[3];
  226.     }
  227.  
  228.   if (is_indexed)
  229.     curves_dialog->col_value [GIMP_HISTOGRAM_ALPHA] = color[4];
  230.  
  231.   maxval = MAX (color[RED_PIX], color[GREEN_PIX]);
  232.   curves_dialog->col_value[GIMP_HISTOGRAM_VALUE] = MAX (maxval, color[BLUE_PIX]);
  233.  
  234.   g_free (color);
  235. }
  236.  
  237. static void
  238. curves_add_point (GimpDrawable *drawable,
  239.           gint          x,
  240.           gint          y,
  241.           gint          cchan)
  242. {
  243.   /* Add point onto the curve */
  244.   gint closest_point = 0;
  245.   gint distance;
  246.   gint curvex;
  247.   gint i;
  248.  
  249.   switch (curves_dialog->curve_type[cchan])
  250.     {
  251.     case SMOOTH:
  252.       curvex = curves_dialog->col_value[cchan];
  253.       distance = G_MAXINT;
  254.       for (i = 0; i < 17; i++)
  255.     {
  256.       if (curves_dialog->points[cchan][i][0] != -1)
  257.         if (abs (curvex - curves_dialog->points[cchan][i][0]) < distance)
  258.           {
  259.         distance = abs (curvex - curves_dialog->points[cchan][i][0]);
  260.         closest_point = i;
  261.           }
  262.     }
  263.       
  264.       if (distance > MIN_DISTANCE)
  265.     closest_point = (curvex + 8) / 16;
  266.       
  267.       curves_dialog->points[cchan][closest_point][0] = curvex;
  268.       curves_dialog->points[cchan][closest_point][1] = curves_dialog->curve[cchan][curvex];
  269.       break;
  270.       
  271.     case GFREE:
  272.       curves_dialog->curve[cchan][x] = 255 - y;
  273.       break;
  274.     }
  275. }
  276.  
  277. /*  curves action functions  */
  278.  
  279. static void
  280. curves_button_press (Tool           *tool,
  281.              GdkEventButton *bevent,
  282.              gpointer        gdisp_ptr)
  283. {
  284.   gint x, y;
  285.   GDisplay     *gdisp;
  286.   GimpDrawable *drawable;
  287.  
  288.   gdisp = gdisp_ptr;
  289.   drawable = gimage_active_drawable (gdisp->gimage);
  290.  
  291.   tool->gdisp_ptr = gdisp;
  292.  
  293.   if (drawable != tool->drawable)
  294.     {
  295.       active_tool->preserve = TRUE;
  296.       image_map_abort (curves_dialog->image_map);
  297.       active_tool->preserve = FALSE;
  298.  
  299.       tool->drawable = drawable;
  300.  
  301.       curves_dialog->drawable = drawable;
  302.       curves_dialog->color = drawable_color (drawable);
  303.       curves_dialog->image_map = image_map_create (gdisp, drawable);
  304.     }
  305.  
  306.   tool->state = ACTIVE;
  307.  
  308.   gdisplay_untransform_coords (gdisp, bevent->x, bevent->y, &x, &y,
  309.                    FALSE, FALSE);
  310.   curves_colour_update (tool, gdisp, drawable, x, y);
  311.   curves_update (curves_dialog, GRAPH | DRAW);
  312. }
  313.  
  314. static void
  315. curves_button_release (Tool           *tool,
  316.                GdkEventButton *bevent,
  317.                gpointer        gdisp_ptr)
  318. {
  319.   gint x, y;
  320.   GimpDrawable *drawable;
  321.   GDisplay     *gdisp;
  322.  
  323.   gdisp = (GDisplay *) gdisp_ptr;
  324.  
  325.   if(!curves_dialog || 
  326.      !gdisp || 
  327.      !(drawable = gimage_active_drawable (gdisp->gimage)))
  328.      return;
  329.  
  330.   gdisplay_untransform_coords (gdisp, bevent->x, bevent->y, &x, &y, FALSE, FALSE);
  331.   curves_colour_update (tool, gdisp, drawable, x, y);
  332.  
  333.   if (bevent->state & GDK_SHIFT_MASK)
  334.     {
  335.       curves_add_point (drawable, x, y, curves_dialog->channel);
  336.       curves_calculate_curve (curves_dialog);
  337.     }
  338.   else if (bevent->state & GDK_CONTROL_MASK)
  339.     {
  340.       curves_add_point (drawable, x, y, GIMP_HISTOGRAM_VALUE);
  341.       curves_add_point (drawable, x, y, GIMP_HISTOGRAM_RED);
  342.       curves_add_point (drawable, x, y, GIMP_HISTOGRAM_GREEN);
  343.       curves_add_point (drawable, x, y, GIMP_HISTOGRAM_BLUE);
  344.       curves_add_point (drawable, x, y, GIMP_HISTOGRAM_ALPHA);
  345.       curves_calculate_curve (curves_dialog);
  346.     }
  347.  
  348.   curves_update (curves_dialog, GRAPH | DRAW);
  349. }
  350.  
  351. static void
  352. curves_motion (Tool           *tool,
  353.            GdkEventMotion *mevent,
  354.            gpointer        gdisp_ptr)
  355. {
  356.   gint x, y;
  357.   GDisplay     *gdisp;
  358.   GimpDrawable *drawable;
  359.  
  360.   gdisp = (GDisplay *) gdisp_ptr;
  361.  
  362.   if(!curves_dialog || 
  363.      !gdisp || 
  364.      !(drawable = gimage_active_drawable (gdisp->gimage)))
  365.      return;
  366.  
  367.   gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, FALSE, FALSE);
  368.   curves_colour_update (tool, gdisp, drawable, x, y);
  369.   curves_update (curves_dialog, GRAPH | DRAW);
  370. }
  371.  
  372. static void
  373. curves_control (Tool       *tool,
  374.         ToolAction  action,
  375.         gpointer    gdisp_ptr)
  376. {
  377.   switch (action)
  378.     {
  379.     case PAUSE:
  380.       break;
  381.  
  382.     case RESUME:
  383.       break;
  384.  
  385.     case HALT:
  386.       curves_dialog_hide ();
  387.       break;
  388.  
  389.     default:
  390.       break;
  391.     }
  392. }
  393.  
  394. Tool *
  395. tools_new_curves (void)
  396. {
  397.   Tool   *tool;
  398.   Curves *private;
  399.  
  400.   /*  The tool options  */
  401.   if (!curves_options)
  402.     {
  403.       curves_options = tool_options_new (_("Curves"));
  404.       tools_register (CURVES, curves_options);
  405.     }
  406.  
  407.   tool = tools_new_tool (CURVES);
  408.   private = g_new0 (Curves, 1);
  409.  
  410.   tool->scroll_lock = TRUE;   /*  Disallow scrolling  */
  411.   tool->preserve    = FALSE;  /*  Don't preserve on drawable change  */
  412.  
  413.   tool->private = (void *) private;
  414.  
  415.   tool->button_press_func   = curves_button_press;
  416.   tool->button_release_func = curves_button_release;
  417.   tool->motion_func         = curves_motion;
  418.   tool->control_func        = curves_control;
  419.  
  420.   return tool;
  421. }
  422.  
  423. void
  424. curves_dialog_hide (void)
  425. {
  426.   if (curves_dialog)
  427.     curves_cancel_callback (NULL, (gpointer) curves_dialog);
  428. }
  429.  
  430. void
  431. tools_free_curves (Tool *tool)
  432. {
  433.   Curves *private;
  434.  
  435.   private = (Curves *) tool->private;
  436.  
  437.   /*  Close the color select dialog  */
  438.   curves_dialog_hide ();
  439.  
  440.   g_free (private);
  441. }
  442.  
  443. void
  444. curves_initialize (GDisplay *gdisp)
  445. {
  446.   gint i, j;
  447.  
  448.   if (gimp_image_is_empty (gdisp->gimage))
  449.     {
  450.       g_message (_("The image has no drawables."));
  451.       return;
  452.     }
  453.  
  454.   if (drawable_indexed (gimage_active_drawable (gdisp->gimage)))
  455.     {
  456.       g_message (_("Curves for indexed drawables cannot be adjusted."));
  457.       return;
  458.     }
  459.  
  460.   /*  The curves dialog  */
  461.   if (!curves_dialog)
  462.     {
  463.       curves_dialog = curves_dialog_new ();
  464.     }
  465.      
  466.   /*  Initialize the values  */
  467.   curves_dialog->channel = GIMP_HISTOGRAM_VALUE;
  468.   for (i = 0; i < 5; i++)
  469.     for (j = 0; j < 256; j++)
  470.       curves_dialog->curve[i][j] = j;
  471.   
  472.   for (i = 0; i < 5; i++)
  473.     {
  474.       curves_channel_reset (i);
  475.     }
  476.  
  477.   curves_dialog->drawable  = gimage_active_drawable (gdisp->gimage);
  478.   curves_dialog->color     = drawable_color (curves_dialog->drawable);
  479.   curves_dialog->image_map = image_map_create (gdisp, curves_dialog->drawable);
  480.  
  481.   /* check for alpha channel */
  482.   if (drawable_has_alpha (curves_dialog->drawable))
  483.     gtk_widget_set_sensitive (channel_items[4], TRUE);
  484.   else 
  485.     gtk_widget_set_sensitive (channel_items[4], FALSE);
  486.   
  487.   /*  hide or show the channel menu based on image type  */
  488.   if (curves_dialog->color)
  489.     for (i = 0; i < 4; i++) 
  490.        gtk_widget_set_sensitive (channel_items[i], TRUE);
  491.   else 
  492.     for (i = 1; i < 4; i++) 
  493.       gtk_widget_set_sensitive (channel_items[i], FALSE);
  494.  
  495.   /* set the current selection */
  496.   gtk_option_menu_set_history (GTK_OPTION_MENU (curves_dialog->channel_menu),
  497.                    curves_dialog->channel);
  498.  
  499.   gimp_lut_setup (curves_dialog->lut, 
  500.           (GimpLutFunc) curves_lut_func,
  501.                   (void *) curves_dialog, 
  502.           gimp_drawable_bytes (curves_dialog->drawable));
  503.  
  504.   if (!GTK_WIDGET_VISIBLE (curves_dialog->shell))
  505.     gtk_widget_show (curves_dialog->shell);
  506.  
  507.   curves_update (curves_dialog, GRAPH | DRAW);
  508.  
  509.   /* Merge-related undo release signal */
  510.  
  511.   curves_dialog->conn_id =
  512.     gtk_signal_connect (GTK_OBJECT (gdisp->gimage), "layer_merge",
  513.             GTK_SIGNAL_FUNC (curves_cancel_callback),
  514.             curves_dialog);
  515. }
  516.  
  517. void
  518. curves_free (void)
  519. {
  520.   if (curves_dialog)
  521.     {
  522.       if (curves_dialog->image_map)
  523.     {
  524.       active_tool->preserve = TRUE;
  525.       image_map_abort (curves_dialog->image_map);
  526.       active_tool->preserve = FALSE;
  527.  
  528.       curves_dialog->image_map = NULL;
  529.  
  530.       if(curves_dialog->conn_id != 0)
  531.         gtk_signal_disconnect (
  532.                    GTK_OBJECT (gimp_drawable_gimage (curves_dialog->drawable)),
  533.                    curves_dialog->conn_id 
  534.                   );
  535.     }
  536.  
  537.       if (curves_dialog->pixmap)
  538.     gdk_pixmap_unref (curves_dialog->pixmap);
  539.  
  540.       gtk_widget_destroy (curves_dialog->shell);
  541.     }
  542. }
  543.  
  544. /*******************/
  545. /*  Curves dialog  */
  546. /*******************/
  547.  
  548. static CurvesDialog *
  549. curves_dialog_new (void)
  550. {
  551.   CurvesDialog *cd;
  552.   GtkWidget *vbox;
  553.   GtkWidget *hbox;
  554.   GtkWidget *hbbox;
  555.   GtkWidget *label;
  556.   GtkWidget *frame;
  557.   GtkWidget *toggle;
  558.   GtkWidget *channel_hbox;
  559.   GtkWidget *table;
  560.   GtkWidget *button;
  561.   gint i, j;
  562.  
  563.   cd = g_new (CurvesDialog, 1);
  564.   cd->cursor_ind_height = -1;
  565.   cd->cursor_ind_width  = -1;
  566.   cd->preview           = TRUE;
  567.   cd->pixmap            = NULL;
  568.   cd->channel           = GIMP_HISTOGRAM_VALUE;
  569.  
  570.   for (i = 0; i < 5; i++)
  571.     cd->curve_type[i] = SMOOTH;
  572.  
  573.   for (i = 0; i < 5; i++)
  574.     for (j = 0; j < 256; j++)
  575.       cd->curve[i][j] = j;
  576.  
  577.   for (i = 0; i < (sizeof (cd->col_value) / sizeof (cd->col_value[0])); i++)
  578.     cd->col_value[i] = 0;
  579.  
  580.   cd->lut = gimp_lut_new ();
  581.  
  582.   /*  The shell and main vbox  */
  583.   cd->shell = gimp_dialog_new (_("Curves"), "curves",
  584.                    tools_help_func, tool_info[CURVES].private_tip,
  585.                    GTK_WIN_POS_NONE,
  586.                    FALSE, TRUE, FALSE,
  587.  
  588.                    _("OK"), curves_ok_callback,
  589.                    cd, NULL, NULL, TRUE, FALSE,
  590.                    _("Reset"), curves_reset_callback,
  591.                    cd, NULL, NULL, FALSE, FALSE,
  592.                    _("Cancel"), curves_cancel_callback,
  593.                    cd, NULL, NULL, FALSE, TRUE,
  594.  
  595.                    NULL);
  596.  
  597.   vbox = gtk_vbox_new (FALSE, 4);
  598.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  599.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (cd->shell)->vbox), vbox);
  600.  
  601.   /*  The option menu for selecting channels  */
  602.   channel_hbox = gtk_hbox_new (FALSE, 4);
  603.   gtk_box_pack_start (GTK_BOX (vbox), channel_hbox, FALSE, FALSE, 0);
  604.  
  605.   label = gtk_label_new (_("Modify Curves for Channel:"));
  606.   gtk_box_pack_start (GTK_BOX (channel_hbox), label, FALSE, FALSE, 0);
  607.  
  608.   cd->channel_menu = gimp_option_menu_new2
  609.     (FALSE, curves_channel_callback,
  610.      cd, GINT_TO_POINTER (cd->channel),
  611.  
  612.      _("Value"), GINT_TO_POINTER (GIMP_HISTOGRAM_VALUE), &channel_items[0],
  613.      _("Red"),   GINT_TO_POINTER (GIMP_HISTOGRAM_RED),   &channel_items[1],
  614.      _("Green"), GINT_TO_POINTER (GIMP_HISTOGRAM_GREEN), &channel_items[2],
  615.      _("Blue"),  GINT_TO_POINTER (GIMP_HISTOGRAM_BLUE),  &channel_items[3],
  616.      _("Alpha"), GINT_TO_POINTER (GIMP_HISTOGRAM_ALPHA), &channel_items[4],
  617.  
  618.      NULL);
  619.  
  620.   gtk_box_pack_start (GTK_BOX (channel_hbox), cd->channel_menu, FALSE, FALSE, 2);
  621.  
  622.   gtk_widget_show (label);
  623.   gtk_widget_show (cd->channel_menu);
  624.   gtk_widget_show (channel_hbox);
  625.  
  626.   /*  The table for the yrange and the graph  */
  627.   table = gtk_table_new (2, 2, FALSE);
  628.   gtk_table_set_col_spacings (GTK_TABLE (table), 2);
  629.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  630.   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
  631.  
  632.   /*  The range drawing area  */
  633.   frame = gtk_frame_new (NULL);
  634.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  635.   gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1,
  636.             GTK_EXPAND, GTK_EXPAND, 0, 0);
  637.  
  638.   cd->yrange = gtk_preview_new (GTK_PREVIEW_COLOR);
  639.   gtk_preview_size (GTK_PREVIEW (cd->yrange), YRANGE_WIDTH, YRANGE_HEIGHT);
  640.   gtk_widget_set_events (cd->yrange, RANGE_MASK);
  641.   gtk_container_add (GTK_CONTAINER (frame), cd->yrange);
  642.  
  643.   gtk_signal_connect (GTK_OBJECT (cd->yrange), "event",
  644.               GTK_SIGNAL_FUNC (curves_yrange_events),
  645.               cd);
  646.  
  647.   gtk_widget_show (cd->yrange);
  648.   gtk_widget_show (frame);
  649.  
  650.   /*  The curves graph  */
  651.   frame = gtk_frame_new (NULL);
  652.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  653.   gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
  654.             GTK_SHRINK | GTK_FILL,
  655.             GTK_SHRINK | GTK_FILL, 0, 0);
  656.  
  657.   cd->graph = gtk_drawing_area_new ();
  658.   gtk_drawing_area_size (GTK_DRAWING_AREA (cd->graph),
  659.              GRAPH_WIDTH + RADIUS * 2,
  660.              GRAPH_HEIGHT + RADIUS * 2);
  661.   gtk_widget_set_events (cd->graph, GRAPH_MASK);
  662.   gtk_container_add (GTK_CONTAINER (frame), cd->graph);
  663.  
  664.   gtk_signal_connect (GTK_OBJECT (cd->graph), "event",
  665.               GTK_SIGNAL_FUNC (curves_graph_events),
  666.               cd);
  667.  
  668.   gtk_widget_show (cd->graph);
  669.   gtk_widget_show (frame);
  670.  
  671.   /*  The range drawing area  */
  672.   frame = gtk_frame_new (NULL);
  673.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  674.   gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 1, 2,
  675.             GTK_EXPAND, GTK_EXPAND, 0, 0);
  676.  
  677.   cd->xrange = gtk_preview_new (GTK_PREVIEW_COLOR);
  678.   gtk_preview_size (GTK_PREVIEW (cd->xrange), XRANGE_WIDTH, XRANGE_HEIGHT);
  679.   gtk_widget_set_events (cd->xrange, RANGE_MASK);
  680.   gtk_container_add (GTK_CONTAINER (frame), cd->xrange);
  681.  
  682.   gtk_signal_connect (GTK_OBJECT (cd->xrange), "event",
  683.               GTK_SIGNAL_FUNC (curves_xrange_events),
  684.               cd);
  685.  
  686.   gtk_widget_show (cd->xrange);
  687.   gtk_widget_show (frame);
  688.   gtk_widget_show (table);
  689.  
  690.   /*  Horizontal box for preview  */
  691.   hbox = gtk_hbox_new (FALSE, 4);
  692.   gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  693.  
  694.   /*  The option menu for selecting the drawing method  */
  695.   label = gtk_label_new (_("Curve Type:"));
  696.   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  697.   gtk_widget_show (label);
  698.  
  699.   cd->curve_type_menu = gimp_option_menu_new
  700.     (FALSE,
  701.  
  702.      _("Smooth"), curves_smooth_callback, cd, NULL, NULL, TRUE,
  703.      _("Free"),   curves_free_callback,   cd, NULL, NULL, FALSE,
  704.  
  705.      NULL);
  706.   gtk_box_pack_start (GTK_BOX (hbox), cd->curve_type_menu, FALSE, FALSE, 2);
  707.   gtk_widget_show (cd->curve_type_menu);
  708.  
  709.   gtk_widget_show (hbox);
  710.  
  711.   /*  The preview toggle  */
  712.   toggle = gtk_check_button_new_with_label (_("Preview"));
  713.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), cd->preview);
  714.   gtk_box_pack_end (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
  715.  
  716.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  717.               GTK_SIGNAL_FUNC (curves_preview_update),
  718.               cd);
  719.  
  720.   gtk_widget_show (toggle);
  721.   gtk_widget_show (hbox);
  722.  
  723.   /*  Horizontal button box for load / save  */
  724.   hbbox = gtk_hbutton_box_new ();
  725.   gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbbox), 4);
  726.   gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_SPREAD);
  727.   gtk_box_pack_end (GTK_BOX (vbox), hbbox, FALSE, FALSE, 0);
  728.  
  729.   button = gtk_button_new_with_label (_("Load"));
  730.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  731.   gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
  732.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  733.               GTK_SIGNAL_FUNC (curves_load_callback),
  734.               cd->shell);
  735.   gtk_widget_show (button);
  736.  
  737.   button = gtk_button_new_with_label (_("Save"));
  738.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  739.   gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
  740.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  741.               GTK_SIGNAL_FUNC (curves_save_callback),
  742.               cd->shell);
  743.   gtk_widget_show (button);
  744.  
  745.   gtk_widget_show (hbbox);
  746.   gtk_widget_show (vbox);
  747.  
  748.   return cd;
  749. }
  750.  
  751. static void
  752. curve_print_loc (CurvesDialog *cd,
  753.          gint          xpos,
  754.          gint          ypos)
  755. {
  756.   gchar buf[32];
  757.   gint  width;
  758.   gint  ascent;
  759.   gint  descent;
  760.  
  761.   if (cd->cursor_ind_width < 0)
  762.     {
  763.       /* Calc max extents */
  764.       gdk_string_extents (cd->graph->style->font,
  765.               "x:888 y:888",
  766.               NULL,
  767.               NULL,
  768.               &width,
  769.               &ascent,
  770.               &descent);
  771.     
  772.       cd->cursor_ind_width = width;
  773.       cd->cursor_ind_height = ascent + descent;
  774.       cd->cursor_ind_ascent = ascent;
  775.     }
  776.   
  777.   if (xpos >= 0 && xpos <= 255 && ypos >=0 && ypos <= 255)
  778.     {
  779.       g_snprintf (buf, sizeof (buf), "x:%d y:%d",xpos,ypos);
  780.  
  781.       gdk_draw_rectangle (cd->graph->window, 
  782.               cd->graph->style->bg_gc[GTK_STATE_ACTIVE],
  783.               TRUE, RADIUS*2 + 2 , RADIUS*2 + 2, 
  784.               cd->cursor_ind_width+4, 
  785.               cd->cursor_ind_height+5);
  786.  
  787.       gdk_draw_rectangle (cd->graph->window, 
  788.               cd->graph->style->black_gc,
  789.               FALSE, RADIUS*2 + 2 , RADIUS*2 + 2, 
  790.               cd->cursor_ind_width+3, 
  791.               cd->cursor_ind_height+4);
  792.  
  793.       gdk_draw_string (cd->graph->window,
  794.                cd->graph->style->font,
  795.                cd->graph->style->black_gc,
  796.                RADIUS*2 + 4,
  797.                RADIUS*2 + 5 + cd->cursor_ind_ascent,
  798.                buf);
  799.     }
  800. }
  801.  
  802. /* TODO: preview alpha channel stuff correctly.  -- austin, 20/May/99 */
  803. static void
  804. curves_update (CurvesDialog *cd,
  805.            gint          update)
  806. {
  807.   GdkRectangle area;
  808.   gint   i, j;
  809.   gchar  buf[32];
  810.   gint   offset;
  811.   gint   sel_channel;
  812.   
  813.   if(cd->color) {
  814.     sel_channel = cd->channel;
  815.   } else {
  816.     if(cd->channel == 2)
  817.       sel_channel = GIMP_HISTOGRAM_ALPHA;
  818.     else
  819.       sel_channel = GIMP_HISTOGRAM_VALUE;
  820.   }
  821.  
  822.  
  823.   if (update & XRANGE_TOP)
  824.     {
  825.       guchar buf[XRANGE_WIDTH * 3];
  826.  
  827.       switch (sel_channel)
  828.     {
  829.     case GIMP_HISTOGRAM_VALUE:
  830.     case GIMP_HISTOGRAM_ALPHA:
  831.       for (i = 0; i < XRANGE_HEIGHT / 2; i++)
  832.         {
  833.           for (j = 0; j < XRANGE_WIDTH ; j++)
  834.         {
  835.           buf[j*3+0] = cd->curve[sel_channel][j];
  836.           buf[j*3+1] = cd->curve[sel_channel][j];
  837.           buf[j*3+2] = cd->curve[sel_channel][j];
  838.         }
  839.           gtk_preview_draw_row (GTK_PREVIEW (cd->xrange),
  840.                     buf, 0, i, XRANGE_WIDTH);
  841.         }
  842.       break;
  843.  
  844.     case GIMP_HISTOGRAM_RED:
  845.     case GIMP_HISTOGRAM_GREEN:
  846.     case GIMP_HISTOGRAM_BLUE:
  847.       {
  848.         for (i = 0; i < XRANGE_HEIGHT / 2; i++)
  849.           {
  850.         for (j = 0; j < XRANGE_WIDTH; j++)
  851.           {
  852.             buf[j*3+0] = cd->curve[GIMP_HISTOGRAM_RED][j];
  853.             buf[j*3+1] = cd->curve[GIMP_HISTOGRAM_GREEN][j];
  854.             buf[j*3+2] = cd->curve[GIMP_HISTOGRAM_BLUE][j];
  855.           }
  856.         gtk_preview_draw_row (GTK_PREVIEW (cd->xrange),
  857.                       buf, 0, i, XRANGE_WIDTH);
  858.           }
  859.         break;
  860.       }
  861.  
  862.     default:
  863.       g_warning ("unknown channel type %d, can't happen!?!?",
  864.              cd->channel);
  865.       break;
  866.     }
  867.  
  868.       if (update & DRAW)
  869.     {
  870.       area.x = 0;
  871.       area.y = 0;
  872.       area.width = XRANGE_WIDTH;
  873.       area.height = XRANGE_HEIGHT / 2;
  874.       gtk_widget_draw (cd->xrange, &area);
  875.     }
  876.     }
  877.   if (update & XRANGE_BOTTOM)
  878.     {
  879.       guchar buf[XRANGE_WIDTH * 3];
  880.  
  881.       for (i = 0; i < XRANGE_WIDTH; i++)
  882.       {
  883.     buf[i*3+0] = i;
  884.     buf[i*3+1] = i;
  885.     buf[i*3+2] = i;
  886.       }
  887.  
  888.       for (i = XRANGE_HEIGHT / 2; i < XRANGE_HEIGHT; i++)
  889.     gtk_preview_draw_row (GTK_PREVIEW (cd->xrange), buf, 0, i, XRANGE_WIDTH);
  890.  
  891.       if (update & DRAW)
  892.     {
  893.       area.x = 0;
  894.       area.y = XRANGE_HEIGHT / 2;
  895.       area.width = XRANGE_WIDTH;
  896.       area.height = XRANGE_HEIGHT / 2;
  897.       gtk_widget_draw (cd->xrange, &area);
  898.     }
  899.     }
  900.   if (update & YRANGE)
  901.     {
  902.       guchar buf[YRANGE_WIDTH * 3];
  903.       guchar pix[3];
  904.  
  905.       for (i = 0; i < YRANGE_HEIGHT; i++)
  906.     {
  907.       switch (sel_channel)
  908.         {
  909.         case GIMP_HISTOGRAM_VALUE:
  910.         case GIMP_HISTOGRAM_ALPHA:
  911.           pix[0] = pix[1] = pix[2] = (255 - i);
  912.           break;
  913.  
  914.         case GIMP_HISTOGRAM_RED:
  915.         case GIMP_HISTOGRAM_GREEN:
  916.         case GIMP_HISTOGRAM_BLUE:
  917.           pix[0] = pix[1] = pix[2] = 0;
  918.           pix[sel_channel - 1] = (255 - i);
  919.           break;
  920.  
  921.         default:
  922.           g_warning ("unknown channel type %d, can't happen!?!?",
  923.              cd->channel);
  924.           break;
  925.         }
  926.  
  927.       for (j = 0; j < YRANGE_WIDTH * 3; j++)
  928.         buf[j] = pix[j%3];
  929.  
  930.       gtk_preview_draw_row (GTK_PREVIEW (cd->yrange),
  931.                 buf, 0, i, YRANGE_WIDTH);
  932.     }
  933.  
  934.       if (update & DRAW)
  935.     gtk_widget_draw (cd->yrange, NULL);
  936.     }
  937.   if ((update & GRAPH) && (update & DRAW) && cd->pixmap != NULL)
  938.     {
  939.       GdkPoint points[256];
  940.  
  941.       /*  Clear the pixmap  */
  942.       gdk_draw_rectangle (cd->pixmap, cd->graph->style->bg_gc[GTK_STATE_NORMAL],
  943.               TRUE, 0, 0,
  944.               GRAPH_WIDTH + RADIUS * 2, GRAPH_HEIGHT + RADIUS * 2);
  945.  
  946.       /*  Draw the grid lines  */
  947.       for (i = 0; i < 5; i++)
  948.     {
  949.       gdk_draw_line (cd->pixmap, cd->graph->style->dark_gc[GTK_STATE_NORMAL],
  950.              RADIUS, i * (GRAPH_HEIGHT / 4) + RADIUS,
  951.              GRAPH_WIDTH + RADIUS, i * (GRAPH_HEIGHT / 4) + RADIUS);
  952.       gdk_draw_line (cd->pixmap, cd->graph->style->dark_gc[GTK_STATE_NORMAL],
  953.              i * (GRAPH_WIDTH / 4) + RADIUS, RADIUS,
  954.              i * (GRAPH_WIDTH / 4) + RADIUS, GRAPH_HEIGHT + RADIUS);
  955.     }
  956.  
  957.       /*  Draw the curve  */
  958.       for (i = 0; i < 256; i++)
  959.     {
  960.       points[i].x = i + RADIUS;
  961.       points[i].y = 255 - cd->curve[cd->channel][i] + RADIUS;
  962.     }
  963.       gdk_draw_points (cd->pixmap, cd->graph->style->black_gc, points, 256);
  964.  
  965.       /*  Draw the points  */
  966.       if (cd->curve_type[cd->channel] == SMOOTH)
  967.     for (i = 0; i < 17; i++)
  968.       {
  969.         if (cd->points[cd->channel][i][0] != -1)
  970.           gdk_draw_arc (cd->pixmap, cd->graph->style->black_gc, TRUE,
  971.                 cd->points[cd->channel][i][0],
  972.                 255 - cd->points[cd->channel][i][1],
  973.                 RADIUS * 2, RADIUS * 2, 0, 23040);
  974.       }
  975.  
  976.       /* draw the colour line */
  977.       gdk_draw_line (cd->pixmap, cd->graph->style->black_gc,
  978.              cd->col_value[sel_channel]+RADIUS,RADIUS,
  979.              cd->col_value[sel_channel]+RADIUS,GRAPH_HEIGHT + RADIUS);
  980.  
  981.       /* and xpos indicator */
  982.       g_snprintf (buf, sizeof (buf), "x:%d",cd->col_value[sel_channel]);
  983.       
  984.       if ((cd->col_value[sel_channel]+RADIUS) < 127)
  985.     {
  986.       offset = RADIUS + 4;
  987.     }
  988.       else
  989.     {
  990.       offset = - gdk_string_width (cd->graph->style->font,buf) - 2;
  991.     }
  992.  
  993.       gdk_draw_string (cd->pixmap,
  994.                cd->graph->style->font,
  995.                cd->graph->style->black_gc,
  996.                cd->col_value[sel_channel]+offset,
  997.                GRAPH_HEIGHT,
  998.                buf);
  999.  
  1000.       gdk_draw_pixmap (cd->graph->window, cd->graph->style->black_gc, cd->pixmap,
  1001.                0, 0, 0, 0, GRAPH_WIDTH + RADIUS * 2, GRAPH_HEIGHT + RADIUS * 2);
  1002.       
  1003.     }
  1004. }
  1005.  
  1006. static void
  1007. curves_plot_curve (CurvesDialog *cd,
  1008.            gint          p1,
  1009.            gint          p2,
  1010.            gint          p3,
  1011.            gint          p4)
  1012. {
  1013.   CRMatrix geometry;
  1014.   CRMatrix tmp1, tmp2;
  1015.   CRMatrix deltas;
  1016.   gdouble  x, dx, dx2, dx3;
  1017.   gdouble  y, dy, dy2, dy3;
  1018.   gdouble  d, d2, d3;
  1019.   gint     lastx, lasty;
  1020.   gint32   newx, newy;
  1021.   gint     i;
  1022.  
  1023.   /* construct the geometry matrix from the segment */
  1024.   for (i = 0; i < 4; i++)
  1025.     {
  1026.       geometry[i][2] = 0;
  1027.       geometry[i][3] = 0;
  1028.     }
  1029.  
  1030.   for (i = 0; i < 2; i++)
  1031.     {
  1032.       geometry[0][i] = cd->points[cd->channel][p1][i];
  1033.       geometry[1][i] = cd->points[cd->channel][p2][i];
  1034.       geometry[2][i] = cd->points[cd->channel][p3][i];
  1035.       geometry[3][i] = cd->points[cd->channel][p4][i];
  1036.     }
  1037.  
  1038.   /* subdivide the curve 1000 times */
  1039.   /* n can be adjusted to give a finer or coarser curve */
  1040.   d = 1.0 / 1000;
  1041.   d2 = d * d;
  1042.   d3 = d * d * d;
  1043.  
  1044.   /* construct a temporary matrix for determining the forward differencing deltas */
  1045.   tmp2[0][0] = 0;     tmp2[0][1] = 0;     tmp2[0][2] = 0;    tmp2[0][3] = 1;
  1046.   tmp2[1][0] = d3;    tmp2[1][1] = d2;    tmp2[1][2] = d;    tmp2[1][3] = 0;
  1047.   tmp2[2][0] = 6*d3;  tmp2[2][1] = 2*d2;  tmp2[2][2] = 0;    tmp2[2][3] = 0;
  1048.   tmp2[3][0] = 6*d3;  tmp2[3][1] = 0;     tmp2[3][2] = 0;    tmp2[3][3] = 0;
  1049.  
  1050.   /* compose the basis and geometry matrices */
  1051.   curves_CR_compose (CR_basis, geometry, tmp1);
  1052.  
  1053.   /* compose the above results to get the deltas matrix */
  1054.   curves_CR_compose (tmp2, tmp1, deltas);
  1055.  
  1056.   /* extract the x deltas */
  1057.   x = deltas[0][0];
  1058.   dx = deltas[1][0];
  1059.   dx2 = deltas[2][0];
  1060.   dx3 = deltas[3][0];
  1061.  
  1062.   /* extract the y deltas */
  1063.   y = deltas[0][1];
  1064.   dy = deltas[1][1];
  1065.   dy2 = deltas[2][1];
  1066.   dy3 = deltas[3][1];
  1067.  
  1068.   lastx = CLAMP (x, 0, 255);
  1069.   lasty = CLAMP (y, 0, 255);
  1070.  
  1071.   cd->curve[cd->channel][lastx] = lasty;
  1072.  
  1073.   /* loop over the curve */
  1074.   for (i = 0; i < 1000; i++)
  1075.     {
  1076.       /* increment the x values */
  1077.       x += dx;
  1078.       dx += dx2;
  1079.       dx2 += dx3;
  1080.  
  1081.       /* increment the y values */
  1082.       y += dy;
  1083.       dy += dy2;
  1084.       dy2 += dy3;
  1085.  
  1086.       newx = CLAMP0255 (ROUND (x));
  1087.       newy = CLAMP0255 (ROUND (y));
  1088.  
  1089.       /* if this point is different than the last one...then draw it */
  1090.       if ((lastx != newx) || (lasty != newy))
  1091.     cd->curve[cd->channel][newx] = newy;
  1092.  
  1093.       lastx = newx;
  1094.       lasty = newy;
  1095.     }
  1096. }
  1097.  
  1098. void
  1099. curves_calculate_curve (CurvesDialog *cd)
  1100. {
  1101.   gint i;
  1102.   gint points[17];
  1103.   gint num_pts;
  1104.   gint p1, p2, p3, p4;
  1105.  
  1106.   switch (cd->curve_type[cd->channel])
  1107.     {
  1108.     case GFREE:
  1109.       break;
  1110.     case SMOOTH:
  1111.       /*  cycle through the curves  */
  1112.       num_pts = 0;
  1113.       for (i = 0; i < 17; i++)
  1114.     if (cd->points[cd->channel][i][0] != -1)
  1115.       points[num_pts++] = i;
  1116.  
  1117.       /*  Initialize boundary curve points */
  1118.       if (num_pts != 0)
  1119.     {
  1120.       for (i = 0; i < cd->points[cd->channel][points[0]][0]; i++)
  1121.         cd->curve[cd->channel][i] = cd->points[cd->channel][points[0]][1];
  1122.       for (i = cd->points[cd->channel][points[num_pts - 1]][0]; i < 256; i++)
  1123.         cd->curve[cd->channel][i] = cd->points[cd->channel][points[num_pts - 1]][1];
  1124.     }
  1125.  
  1126.       for (i = 0; i < num_pts - 1; i++)
  1127.     {
  1128.       p1 = (i == 0) ? points[i] : points[(i - 1)];
  1129.       p2 = points[i];
  1130.       p3 = points[(i + 1)];
  1131.       p4 = (i == (num_pts - 2)) ? points[(num_pts - 1)] : points[(i + 2)];
  1132.  
  1133.       curves_plot_curve (cd, p1, p2, p3, p4);
  1134.     }
  1135.       break;
  1136.     }
  1137.   gimp_lut_setup (cd->lut, (GimpLutFunc) curves_lut_func,
  1138.           (void *) cd, gimp_drawable_bytes (cd->drawable));
  1139.  
  1140. }
  1141.  
  1142. static void
  1143. curves_preview (CurvesDialog *cd)
  1144. {
  1145.   if (!cd->image_map)
  1146.     {
  1147.       g_message ("curves_preview(): No image map");
  1148.       return;
  1149.     }
  1150.  
  1151.   active_tool->preserve = TRUE;
  1152.   image_map_apply (cd->image_map,  (ImageMapApplyFunc)gimp_lut_process_2,
  1153.            (void *) cd->lut);
  1154.   active_tool->preserve = FALSE;
  1155. }
  1156.  
  1157. static void
  1158. curves_channel_callback (GtkWidget *widget,
  1159.              gpointer   data)
  1160. {
  1161.   CurvesDialog *cd;
  1162.  
  1163.   cd = (CurvesDialog *) data;
  1164.  
  1165.   gimp_menu_item_update (widget, &cd->channel);
  1166.  
  1167.   if(!cd->color) {
  1168.     if(cd->channel > 1)
  1169.       {
  1170.     cd->channel = 2;
  1171.       }
  1172.     else 
  1173.       {
  1174.     cd->channel = 1;
  1175.       }
  1176.   } 
  1177.  
  1178.   gtk_option_menu_set_history (GTK_OPTION_MENU (cd->curve_type_menu), 
  1179.                    cd->curve_type[cd->channel]);
  1180.  
  1181.   curves_update (cd, XRANGE_TOP | YRANGE | GRAPH | DRAW);
  1182. }
  1183.  
  1184. static void
  1185. curves_smooth_callback (GtkWidget *widget,
  1186.             gpointer   data)
  1187. {
  1188.   CurvesDialog *cd;
  1189.   gint   i;
  1190.   gint32 index;
  1191.  
  1192.   cd = (CurvesDialog *) data;
  1193.  
  1194.   if (cd->curve_type[cd->channel] != SMOOTH)
  1195.     {
  1196.       cd->curve_type[cd->channel] = SMOOTH;
  1197.  
  1198.       /*  pick representative points from the curve and make them control points  */
  1199.       for (i = 0; i <= 8; i++)
  1200.     {
  1201.       index = CLAMP0255 (i * 32);
  1202.       cd->points[cd->channel][i * 2][0] = index;
  1203.       cd->points[cd->channel][i * 2][1] = cd->curve[cd->channel][index];
  1204.     }
  1205.  
  1206.       curves_calculate_curve (cd);
  1207.       curves_update (cd, GRAPH | DRAW);
  1208.  
  1209.       if (cd->preview)
  1210.     curves_preview (cd);
  1211.     }
  1212. }
  1213.  
  1214. static void
  1215. curves_free_callback (GtkWidget *widget,
  1216.               gpointer   data)
  1217. {
  1218.   CurvesDialog *cd;
  1219.  
  1220.   cd = (CurvesDialog *) data;
  1221.  
  1222.   if (cd->curve_type[cd->channel] != GFREE)
  1223.     {
  1224.       cd->curve_type[cd->channel] = GFREE;
  1225.       curves_calculate_curve (cd);
  1226.       curves_update (cd, GRAPH | DRAW);
  1227.  
  1228.       if (cd->preview)
  1229.     curves_preview (cd);
  1230.     }
  1231. }
  1232.  
  1233. static void
  1234. curves_channel_reset (int i)
  1235. {
  1236.   gint j;
  1237.  
  1238.   curves_dialog->grab_point = -1;
  1239.  
  1240.   for (j = 0; j < 17; j++)
  1241.   {
  1242.     curves_dialog->points[i][j][0] = -1;
  1243.     curves_dialog->points[i][j][1] = -1;
  1244.   }
  1245.   curves_dialog->points[i][0][0] = 0;
  1246.   curves_dialog->points[i][0][1] = 0;
  1247.   curves_dialog->points[i][16][0] = 255;
  1248.   curves_dialog->points[i][16][1] = 255;
  1249. }
  1250.  
  1251.  
  1252. static void
  1253. curves_reset_callback (GtkWidget *widget,
  1254.                gpointer   data)
  1255. {
  1256.   CurvesDialog *cd;
  1257.   gint i;
  1258.  
  1259.   cd = (CurvesDialog *) data;
  1260.  
  1261.   /*  Initialize the values  */
  1262.   for (i = 0; i < 256; i++)
  1263.     cd->curve[cd->channel][i] = i;
  1264.  
  1265.   curves_channel_reset (cd->channel);
  1266.  
  1267.   curves_calculate_curve (cd);
  1268.   curves_update (cd, GRAPH | XRANGE_TOP | DRAW);
  1269.  
  1270.   if (cd->preview)
  1271.     curves_preview (cd);
  1272. }
  1273.  
  1274. static void
  1275. curves_ok_callback (GtkWidget *widget,
  1276.             gpointer   data)
  1277. {
  1278.   CurvesDialog *cd;
  1279.  
  1280.   cd = (CurvesDialog *) data;
  1281.  
  1282.   gimp_dialog_hide (cd->shell);
  1283.  
  1284.   active_tool->preserve = TRUE;  /* We're about to dirty... */
  1285.  
  1286.   if (!cd->preview)
  1287.     image_map_apply (cd->image_map, (ImageMapApplyFunc)gimp_lut_process_2,
  1288.              (void *) cd->lut);
  1289.  
  1290.   if (cd->image_map)
  1291.     image_map_commit (cd->image_map);
  1292.  
  1293.   active_tool->preserve = FALSE;
  1294.  
  1295.   cd->image_map = NULL;
  1296.  
  1297.   active_tool->gdisp_ptr = NULL;
  1298.   active_tool->drawable = NULL;
  1299. }
  1300.  
  1301. static void
  1302. curves_cancel_callback (GtkWidget *widget,
  1303.             gpointer   data)
  1304. {
  1305.   CurvesDialog *cd;
  1306.  
  1307.   cd = (CurvesDialog *) data;
  1308.  
  1309.   gimp_dialog_hide (cd->shell);
  1310.  
  1311.   if (cd->image_map)
  1312.     {
  1313.       active_tool->preserve = TRUE;
  1314.       image_map_abort (cd->image_map);
  1315.       active_tool->preserve = FALSE;
  1316.  
  1317.       gdisplays_flush ();
  1318.       cd->image_map = NULL;
  1319.     }
  1320.  
  1321.   if (cd->conn_id != 0)
  1322.     {
  1323.       gtk_signal_disconnect (GTK_OBJECT (gimp_drawable_gimage (cd->drawable)), cd->conn_id);
  1324.       cd->conn_id = 0;
  1325.     }
  1326.  
  1327.   active_tool->gdisp_ptr = NULL;
  1328.   active_tool->drawable = NULL;
  1329. }
  1330.  
  1331. static void
  1332. curves_load_callback (GtkWidget *widget,
  1333.               gpointer   data)
  1334. {
  1335.   if (!file_dlg)
  1336.     file_dialog_create (GTK_WIDGET (data));
  1337.   else if (GTK_WIDGET_VISIBLE (file_dlg)) 
  1338.     return;
  1339.  
  1340.   load_save = TRUE;
  1341.  
  1342.   gtk_window_set_title (GTK_WINDOW (file_dlg), _("Load Curves"));
  1343.   gtk_widget_show (file_dlg);
  1344. }
  1345.  
  1346. static void
  1347. curves_save_callback (GtkWidget *widget,
  1348.               gpointer   data)
  1349. {
  1350.   if (!file_dlg)
  1351.     file_dialog_create (GTK_WIDGET (data));
  1352.   else if (GTK_WIDGET_VISIBLE (file_dlg)) 
  1353.     return;
  1354.  
  1355.   load_save = FALSE;
  1356.  
  1357.   gtk_window_set_title (GTK_WINDOW (file_dlg), _("Save Curves"));
  1358.   gtk_widget_show (file_dlg);
  1359. }
  1360.  
  1361. static void
  1362. curves_preview_update (GtkWidget *widget,
  1363.                gpointer   data)
  1364. {
  1365.   CurvesDialog *cd;
  1366.  
  1367.   cd = (CurvesDialog *) data;
  1368.   
  1369.   if (GTK_TOGGLE_BUTTON (widget)->active)
  1370.     {
  1371.       cd->preview = TRUE;
  1372.       curves_preview (cd);
  1373.     }
  1374.   else
  1375.     {
  1376.       cd->preview = FALSE;
  1377.       if (cd->image_map)
  1378.     {
  1379.       active_tool->preserve = TRUE;
  1380.       image_map_clear (cd->image_map);
  1381.       active_tool->preserve = FALSE;
  1382.       gdisplays_flush ();
  1383.     }
  1384.     }
  1385. }
  1386.  
  1387. static gint
  1388. curves_graph_events (GtkWidget    *widget,
  1389.              GdkEvent     *event,
  1390.              CurvesDialog *cd)
  1391. {
  1392.   static GdkCursorType cursor_type = GDK_TOP_LEFT_ARROW;
  1393.   GdkCursorType new_type;
  1394.   GdkEventButton *bevent;
  1395.   GdkEventMotion *mevent;
  1396.   gint i;
  1397.   gint tx, ty;
  1398.   gint x, y;
  1399.   gint closest_point;
  1400.   gint distance;
  1401.   gint x1, x2, y1, y2;
  1402.  
  1403.   new_type      = GDK_X_CURSOR;
  1404.   closest_point = 0;
  1405.  
  1406.   /*  get the pointer position  */
  1407.   gdk_window_get_pointer (cd->graph->window, &tx, &ty, NULL);
  1408.   x = CLAMP ((tx - RADIUS), 0, 255);
  1409.   y = CLAMP ((ty - RADIUS), 0, 255);
  1410.  
  1411.   distance = G_MAXINT;
  1412.   for (i = 0; i < 17; i++)
  1413.     {
  1414.       if (cd->points[cd->channel][i][0] != -1)
  1415.     if (abs (x - cd->points[cd->channel][i][0]) < distance)
  1416.       {
  1417.         distance = abs (x - cd->points[cd->channel][i][0]);
  1418.         closest_point = i;
  1419.       }
  1420.     }
  1421.   if (distance > MIN_DISTANCE)
  1422.     closest_point = (x + 8) / 16;
  1423.  
  1424.   switch (event->type)
  1425.     {
  1426.     case GDK_EXPOSE:
  1427.       if (cd->pixmap == NULL)
  1428.     cd->pixmap = gdk_pixmap_new (cd->graph->window,
  1429.                      GRAPH_WIDTH + RADIUS * 2,
  1430.                      GRAPH_HEIGHT + RADIUS * 2, -1);
  1431.  
  1432.       curves_update (cd, GRAPH | DRAW);
  1433.       break;
  1434.  
  1435.     case GDK_BUTTON_PRESS:
  1436.       bevent = (GdkEventButton *) event;
  1437.       new_type = GDK_TCROSS;
  1438.  
  1439.       switch (cd->curve_type[cd->channel])
  1440.     {
  1441.     case SMOOTH:
  1442.       /*  determine the leftmost and rightmost points  */
  1443.       cd->leftmost = -1;
  1444.       for (i = closest_point - 1; i >= 0; i--)
  1445.         if (cd->points[cd->channel][i][0] != -1)
  1446.           {
  1447.         cd->leftmost = cd->points[cd->channel][i][0];
  1448.         break;
  1449.           }
  1450.       cd->rightmost = 256;
  1451.       for (i = closest_point + 1; i < 17; i++)
  1452.         if (cd->points[cd->channel][i][0] != -1)
  1453.           {
  1454.         cd->rightmost = cd->points[cd->channel][i][0];
  1455.         break;
  1456.           }
  1457.  
  1458.       cd->grab_point = closest_point;
  1459.       cd->points[cd->channel][cd->grab_point][0] = x;
  1460.       cd->points[cd->channel][cd->grab_point][1] = 255 - y;
  1461.  
  1462.       break;
  1463.  
  1464.     case GFREE:
  1465.       cd->curve[cd->channel][x] = 255 - y;
  1466.       cd->grab_point = x;
  1467.       cd->last = y;
  1468.       break;
  1469.     }
  1470.       
  1471.       curves_calculate_curve (cd);
  1472.       curves_update (cd, GRAPH | XRANGE_TOP | DRAW);
  1473.       gtk_grab_add (widget);
  1474.  
  1475.       break;
  1476.  
  1477.     case GDK_BUTTON_RELEASE:
  1478.       new_type = GDK_FLEUR;
  1479.       cd->grab_point = -1;
  1480.  
  1481.       if (cd->preview)
  1482.     curves_preview (cd);
  1483.  
  1484.       gtk_grab_remove (widget);
  1485.  
  1486.       break;
  1487.  
  1488.     case GDK_MOTION_NOTIFY:
  1489.       mevent = (GdkEventMotion *) event;
  1490.  
  1491.       if (mevent->is_hint)
  1492.     {
  1493.       mevent->x = tx;
  1494.       mevent->y = ty;
  1495.     }
  1496.  
  1497.       switch (cd->curve_type[cd->channel])
  1498.     {
  1499.     case SMOOTH:
  1500.       /*  If no point is grabbed...  */
  1501.       if (cd->grab_point == -1)
  1502.         {
  1503.           if (cd->points[cd->channel][closest_point][0] != -1)
  1504.         new_type = GDK_FLEUR;
  1505.           else
  1506.         new_type = GDK_TCROSS;
  1507.         }
  1508.       /*  Else, drag the grabbed point  */
  1509.       else
  1510.         {
  1511.           new_type = GDK_TCROSS;
  1512.  
  1513.           cd->points[cd->channel][cd->grab_point][0] = -1;
  1514.  
  1515.           if (x > cd->leftmost && x < cd->rightmost)
  1516.         {
  1517.           closest_point = (x + 8) / 16;
  1518.           if (cd->points[cd->channel][closest_point][0] == -1)
  1519.             cd->grab_point = closest_point;
  1520.           cd->points[cd->channel][cd->grab_point][0] = x;
  1521.           cd->points[cd->channel][cd->grab_point][1] = 255 - y;
  1522.         }
  1523.  
  1524.           curves_calculate_curve (cd);
  1525.           curves_update (cd, GRAPH | XRANGE_TOP | DRAW);
  1526.         }
  1527.       break;
  1528.  
  1529.     case GFREE:
  1530.       if (cd->grab_point != -1)
  1531.         {
  1532.           if (cd->grab_point > x)
  1533.         {
  1534.           x1 = x;
  1535.           x2 = cd->grab_point;
  1536.           y1 = y;
  1537.           y2 = cd->last;
  1538.         }
  1539.           else
  1540.         {
  1541.           x1 = cd->grab_point;
  1542.           x2 = x;
  1543.           y1 = cd->last;
  1544.           y2 = y;
  1545.         }
  1546.  
  1547.           if (x2 != x1)
  1548.         for (i = x1; i <= x2; i++)
  1549.           cd->curve[cd->channel][i] = 255 - (y1 + ((y2 - y1) * (i - x1)) / (x2 - x1));
  1550.           else
  1551.         cd->curve[cd->channel][x] = 255 - y;
  1552.  
  1553.           cd->grab_point = x;
  1554.           cd->last = y;
  1555.  
  1556.           curves_update (cd, GRAPH | XRANGE_TOP | DRAW);
  1557.         }
  1558.  
  1559.       if (mevent->state & GDK_BUTTON1_MASK)
  1560.         new_type = GDK_TCROSS;
  1561.       else
  1562.         new_type = GDK_PENCIL;
  1563.       break;
  1564.     }
  1565.  
  1566.       if (new_type != cursor_type)
  1567.     {
  1568.       cursor_type = new_type;
  1569.       change_win_cursor (cd->graph->window, cursor_type,
  1570.                  TOOL_TYPE_NONE, CURSOR_MODIFIER_NONE, FALSE);
  1571.     }
  1572.  
  1573.       curve_print_loc (cd, x, 255 - y);
  1574.  
  1575.       break;
  1576.  
  1577.     default:
  1578.       break;
  1579.     }
  1580.  
  1581.   return FALSE;
  1582. }
  1583.  
  1584. static gint
  1585. curves_xrange_events (GtkWidget    *widget,
  1586.               GdkEvent     *event,
  1587.               CurvesDialog *cd)
  1588. {
  1589.   switch (event->type)
  1590.     {
  1591.     case GDK_EXPOSE:
  1592.       curves_update (cd, XRANGE_TOP | XRANGE_BOTTOM);
  1593.       break;
  1594.  
  1595.     case GDK_DELETE:
  1596.       break;
  1597.  
  1598.     default:
  1599.       break;
  1600.     }
  1601.  
  1602.   return FALSE;
  1603. }
  1604.  
  1605. static gint
  1606. curves_yrange_events (GtkWidget    *widget,
  1607.               GdkEvent     *event,
  1608.               CurvesDialog *cd)
  1609. {
  1610.   switch (event->type)
  1611.     {
  1612.     case GDK_EXPOSE:
  1613.       curves_update (cd, YRANGE);
  1614.       break;
  1615.  
  1616.     default:
  1617.       break;
  1618.     }
  1619.  
  1620.   return FALSE;
  1621. }
  1622.  
  1623. static void
  1624. curves_CR_compose (CRMatrix a,
  1625.            CRMatrix b,
  1626.            CRMatrix ab)
  1627. {
  1628.   gint i, j;
  1629.  
  1630.   for (i = 0; i < 4; i++)
  1631.     {
  1632.       for (j = 0; j < 4; j++)
  1633.         {
  1634.           ab[i][j] = (a[i][0] * b[0][j] +
  1635.                       a[i][1] * b[1][j] +
  1636.                       a[i][2] * b[2][j] +
  1637.                       a[i][3] * b[3][j]);
  1638.         }
  1639.     }
  1640. }
  1641.  
  1642.  
  1643. static void
  1644. file_dialog_create (GtkWidget *parent)
  1645. {
  1646.   gchar *temp;
  1647.  
  1648.   file_dlg = gtk_file_selection_new (_("Load/Save Curves"));
  1649.   gtk_window_set_wmclass (GTK_WINDOW (file_dlg), "load_save_curves", "Gimp");
  1650.   gtk_window_set_position (GTK_WINDOW (file_dlg), GTK_WIN_POS_MOUSE);
  1651.  
  1652.   gtk_container_set_border_width (GTK_CONTAINER (file_dlg), 2);
  1653.   gtk_container_set_border_width (GTK_CONTAINER (GTK_FILE_SELECTION (file_dlg)->button_area), 2);
  1654.  
  1655.   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->cancel_button),
  1656.               "clicked", GTK_SIGNAL_FUNC (file_dialog_cancel_callback),
  1657.               NULL);
  1658.   gtk_signal_connect (GTK_OBJECT (file_dlg), "delete_event",
  1659.               GTK_SIGNAL_FUNC (file_dialog_cancel_callback),
  1660.               NULL);
  1661.   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_dlg)->ok_button),
  1662.               "clicked", GTK_SIGNAL_FUNC (file_dialog_ok_callback),
  1663.               NULL);
  1664.  
  1665.   gtk_signal_connect (GTK_OBJECT (parent), "unmap",
  1666.               GTK_SIGNAL_FUNC (file_dialog_cancel_callback),
  1667.               NULL);
  1668.  
  1669.   temp = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "curves" G_DIR_SEPARATOR_S,
  1670.                     gimp_directory ());
  1671.   gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_dlg), temp);
  1672.   g_free (temp);
  1673.  
  1674.   gimp_help_connect_help_accel (file_dlg, tools_help_func,
  1675.                 tool_info[CURVES].private_tip);
  1676. }
  1677.  
  1678. static void
  1679. file_dialog_ok_callback (GtkWidget *widget,
  1680.              gpointer   data)
  1681. {
  1682.   FILE  *f;
  1683.   gchar *filename;
  1684.  
  1685.   filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_dlg));
  1686.  
  1687.   if (load_save)
  1688.     {
  1689.       f = fopen (filename, "rt");
  1690.  
  1691.       if (!f)
  1692.     {
  1693.       g_message (_("Unable to open file %s"), filename);
  1694.       return;
  1695.     }
  1696.  
  1697.       if (!curves_read_from_file (f))
  1698.     {
  1699.       g_message (("Error in reading file %s"), filename);
  1700.       return;
  1701.     }
  1702.  
  1703.       fclose (f);
  1704.     }
  1705.   else
  1706.     {
  1707.       f = fopen (filename, "wt");
  1708.  
  1709.       if (!f)
  1710.     {
  1711.       g_message (_("Unable to open file %s"), filename);
  1712.       return;
  1713.     }
  1714.  
  1715.       curves_write_to_file (f);
  1716.  
  1717.       fclose (f);
  1718.     }
  1719.  
  1720.   file_dialog_cancel_callback (file_dlg, NULL);
  1721. }
  1722.  
  1723. static void
  1724. file_dialog_cancel_callback (GtkWidget *widget,
  1725.                  gpointer   data)
  1726. {
  1727.   gimp_dialog_hide (file_dlg);
  1728. }
  1729.  
  1730. static gboolean
  1731. curves_read_from_file (FILE *f)
  1732. {
  1733.   gint  i, j;
  1734.   gint  fields;
  1735.   gchar buf[50];
  1736.   gint  index[5][17];
  1737.   gint  value[5][17];
  1738.   gint  current_channel;
  1739.   
  1740.   if (!fgets (buf, 50, f))
  1741.     return FALSE;
  1742.  
  1743.   if (strcmp (buf, "# GIMP Curves File\n") != 0)
  1744.     return FALSE;
  1745.  
  1746.   for (i = 0; i < 5; i++)
  1747.     {
  1748.       for (j = 0; j < 17; j++)
  1749.     {
  1750.       fields = fscanf (f, "%d %d ", &index[i][j], &value[i][j]);
  1751.       if (fields != 2)
  1752.         {
  1753.           g_print ("fields != 2");
  1754.           return FALSE;
  1755.         }
  1756.     }
  1757.     }
  1758.  
  1759.   for (i = 0; i < 5; i++)
  1760.     {
  1761.       curves_dialog->curve_type[i] = SMOOTH;
  1762.       for (j = 0; j < 17; j++)
  1763.     {
  1764.       curves_dialog->points[i][j][0] = index[i][j];
  1765.       curves_dialog->points[i][j][1] = value[i][j];
  1766.     }
  1767.     }
  1768.  
  1769.   /* this is ugly, but works ... */
  1770.   current_channel = curves_dialog->channel;
  1771.   for (i = 0; i < 5; i++)
  1772.     {
  1773.       curves_dialog->channel = i;
  1774.       curves_calculate_curve (curves_dialog);
  1775.     }
  1776.   curves_dialog->channel = current_channel;
  1777.  
  1778.   curves_update (curves_dialog, ALL);
  1779.   gtk_option_menu_set_history (GTK_OPTION_MENU (curves_dialog->curve_type_menu),
  1780.                    SMOOTH);
  1781.  
  1782.   if (curves_dialog->preview)
  1783.     curves_preview (curves_dialog);
  1784.  
  1785.   return TRUE;
  1786. }
  1787.  
  1788. static void
  1789. curves_write_to_file (FILE *f)
  1790. {
  1791.   gint   i, j;
  1792.   gint32 index;
  1793.  
  1794.   for (i = 0; i < 5; i++)
  1795.     if (curves_dialog->curve_type[i] == GFREE)
  1796.       {  
  1797.     /*  pick representative points from the curve and make them control points  */
  1798.     for (j = 0; j <= 8; j++)
  1799.       {
  1800.         index = CLAMP0255 (j * 32);
  1801.         curves_dialog->points[i][j * 2][0] = index;
  1802.         curves_dialog->points[i][j * 2][1] = curves_dialog->curve[i][index];
  1803.       }      
  1804.       }
  1805.   
  1806.   fprintf (f, "# GIMP Curves File\n");
  1807.  
  1808.   for (i = 0; i < 5; i++)
  1809.     {
  1810.       for (j = 0; j < 17; j++)
  1811.     fprintf (f, "%d %d ", curves_dialog->points[i][j][0], 
  1812.                       curves_dialog->points[i][j][1]);
  1813.       
  1814.       fprintf (f, "\n");
  1815.     }
  1816. }
  1817.  
  1818.